package com.forsir.android.mhfinance.helper;

public class CalculatorSolver {
	public static String lastExpression = "";

	public static String solve(String expression, boolean usePrecedence) {
		expression = expression.replace("/*", "*");

		String result = ' ' + expression + ' ';
		char cha, operator;
		int leftPosition, rightPosition, operatorPosition;

		// resolve parentheses
		leftPosition = result.indexOf('(');
		while (leftPosition > 0) {
			int count = 1;
			// find right parentheses
			for (rightPosition = leftPosition + 1; rightPosition < result.length() - 1; rightPosition++) {
				cha = result.charAt(rightPosition);
				if (cha == ')') {
					count--;
					if (count == 0) {
						break;
					}
				}
				if (cha == '(') {
					count++;
				}
			}

			final String leftSubstring = prepareLeftString(result.substring(0, leftPosition));
			final String rightSubstring = prepareRightString(result.substring(rightPosition + 1));

			result = leftSubstring + solve(result.substring(leftPosition + 1, rightPosition), usePrecedence) + rightSubstring;
			leftPosition = result.indexOf('(');
		}

		// resolve single right parentheses
		rightPosition = result.indexOf(')');
		while (rightPosition > 0) {
			final String rightSubstring = prepareRightString(result.substring(rightPosition + 1));

			result = ' ' + solve(result.substring(1, rightPosition), usePrecedence) + rightSubstring;
			rightPosition = result.indexOf(')');
		}

		// Implement Compute
		for (int priority = 0; priority < 2; priority++) {
			if (usePrecedence) {
				operatorPosition = findOperatorByPriority(result, priority, 1);
			} else {
				operatorPosition = findFirstOperator(result, 1);
			}
			while (operatorPosition > 0) {
				operator = result.charAt(operatorPosition);
				leftPosition = getLeftOperandBegin(result, operatorPosition);
				rightPosition = getRightOperandEnd(result, operatorPosition);

				result = result.substring(0, leftPosition)
				        + Compute(operator, result.substring(leftPosition, operatorPosition), result.substring(operatorPosition + 1, rightPosition))
				        + result.substring(rightPosition);

				if (usePrecedence) {
					operatorPosition = findOperatorByPriority(result, priority, 2);
				} else {
					operatorPosition = findFirstOperator(result, 2);
				}

			}
		}
		return result.trim();
	}

	private static int findOperatorByPriority(String expresion, int priority, int from) {
		int pos1;
		int pos2;
		if (priority == 0) {
			pos1 = expresion.indexOf('/');
			pos2 = expresion.indexOf('*');
		} else {
			pos1 = expresion.indexOf('+');
			pos2 = expresion.indexOf('-', from);
		}

		if (pos1 == -1) {
			return pos2;
		}

		if (pos2 == -1) {
			return pos1;
		}

		if (pos1 < pos2) {
			return pos1;
		}
		return pos2;
	}

	private static int findFirstOperator(String expresion, int from) {
		final int[] pos = new int[] { 0, 0, 0, 0 };

		pos[0] = expresion.indexOf('/');
		pos[1] = expresion.indexOf('*');
		pos[2] = expresion.indexOf('+');
		pos[3] = expresion.indexOf('-', from);

		int min = -1;

		for (int i = 0; i < 4; i++) {
			if (pos[i] != -1) {
				if (min == -1) {
					min = pos[i];
				} else if (pos[i] < min) {
					min = pos[i];
				}
			}
		}
		return min;
	}

	private static int getLeftOperandBegin(String number, int operatorPosition) {
		char ch;
		operatorPosition--;
		do {
			ch = number.charAt(operatorPosition);
			if (!Character.isDigit(ch)) {
				if (ch != '.' && ch != ',') {
					break;
				}
			}
		} while (operatorPosition-- > 0);

		ch = number.charAt(operatorPosition);
		if (ch == '-') {
			ch = number.charAt(operatorPosition - 1);
			if (!Character.isDigit(ch)) {
				if (ch != '.' && ch != ',') {
					operatorPosition--;
				}
			}
		}

		return operatorPosition + 1;
	}

	private static int getRightOperandEnd(String number, int operatorPosition) {
		char ch;
		operatorPosition++;
		final int length = number.length();
		ch = number.charAt(operatorPosition);

		if (ch == '-' || ch == '+') {
			operatorPosition++;
		}

		do {
			ch = number.charAt(operatorPosition);
			if (!Character.isDigit(ch)) {
				if (ch != '.' && ch != ',') {
					return operatorPosition;
				}
			}
		} while (operatorPosition++ < length);
		return operatorPosition;
	}

	private static String prepareLeftString(String leftString) {
		final char cha = leftString.charAt(leftString.length() - 1);
		if (Character.isDigit(cha) || cha == '.' || cha == ',' || cha == ')') {
			leftString = leftString + '*';
		}

		if (!leftString.startsWith(" ")) {
			leftString = " " + leftString;
		}
		return leftString;
	}

	private static String prepareRightString(String rightString) {
		if (rightString.length() == 0) {
			return " ";
		}

		final char cha = rightString.charAt(0);
		if (Character.isDigit(cha) || cha == '.' || cha == ',' || cha == '(') {
			rightString = '*' + rightString;
		}

		if (!rightString.endsWith(" ")) {
			rightString = rightString + " ";
		}
		return rightString;
	}

	private static String prepareNumber(String number, String neutralNumber) {
		if (number.length() == 0 || number.contentEquals("-") || number.contentEquals("+")) {
			return neutralNumber;
		}

		// for easier computing
		number = number.replace(',', '.');
		final int position = number.lastIndexOf('.');

		if (position > 0) {
			number = number.substring(0, position).replace(".", "") + number.substring(position);
		}
		if (number.equals(".") || number.equals("-.") || number.equals("+.")) {
			return "0";
		}

		return number;
	}

	private static String Compute(char operator, String leftOperand, String rightOperand) {
		float left, right, result = 0;

		if (operator == '*' || operator == '/') {
			left = Float.parseFloat(prepareNumber(leftOperand, "1"));
			right = Float.parseFloat(prepareNumber(rightOperand, "1"));
		} else {
			left = Float.parseFloat(prepareNumber(leftOperand, "0"));
			right = Float.parseFloat(prepareNumber(rightOperand, "0"));
		}

		if (leftOperand.length() == 0) {
			if (rightOperand.length() == 0) {
				return "";
			}
			if (operator == '-') {
				return String.format("%.2f", -right);
			}
			return String.format("%.2f", right);
		}

		if (rightOperand.length() == 0) {
			return String.format("%.2f", left);
		}

		if (operator == '+') {
			result = left + right;
		}
		if (operator == '-') {
			result = left - right;
		}
		if (operator == '*') {
			result = left * right;
		}
		if (operator == '/') {
			result = left / right;
		}

		if (Float.isInfinite(result) || Float.isNaN(result)) {
			result = 0;
		}

		return String.format("%.2f", result);
	}
}
